home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
dm3_src.zip
/
DMTIMEIO.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-10
|
15KB
|
471 lines
;* ************************************************************************* *;
;* *;
;* I B M - P C R E A L T I M E C L O C K R O U T I N E S *;
;* *;
;* ************************************************************************* *;
;==========================
; Data Structure
; Definitions
;==========================
DMTIME struc
;
ttype dw 0 ; Timer type
; 0 = Multiple Event Interval Timer
; 1 = Single Event Countdown Timer
counter dw 0 ; Tick Counter
interval dw 0 ; Interval or Countdown Value
event dw 0 ; Event Flag/Counter
link dd 0 ; Link to next timer
;
DMTIME ends
;==========================
; DOS Interface
; Definitions
;==========================
TIMER_VECTOR equ 08H ; Interval Timer Interrupt Number
DOS equ 21H ; DOS access vector
DOS_SET_VECTOR equ 25H ; Set interrupt vector
DOS_GET_VECTOR equ 35H ; Get interrupt vector
;==========================
; Timer Monitor
; For DM Library
;==========================
DMIOSEG SEGMENT 'CODE'
ASSUME cs:DMIOSEG
;==========================
; Linkage References
;==========================
public _dmtimer_init
public _dmtimer_release
public _dmtimer_add
public _dmtimer_sub
;==========================
; Local Storage
;==========================
timer_table label word ; 1/10 of second flags
db 0,1,0,1,0,1,0,1,0,1
db 1,0,1,0,1,0,1,0,1,0
db 1,1,0,1,0,1,0,1,0,1
db 0,1,1,0,1,0,1,0,1,0
db 1,0,1,1,0,1,0,1,0,1
db 0,1,0,1,1,0,1,0,1,0
db 1,0,1,0,1,1,0,1,0,1
db 0,1,0,1,0,1,1,0,1,0
db 1,0,1,0,1,0,1,1,0,1
db 1
oldint dw offset _dmtimer_isr ; Old interrupt vector
dw seg _dmtimer_isr
timer_tick dw 0 ; Tick counter
root_timer label word ; Root timer
DMTIME <0, 0, 1, 0, 0>
;==========================
; Code Section
;==========================
_dmtimer_init proc far
;
;==========================
; Timer Initialization
;==========================
; Procedure: 1. Save the passed parameters
; 2. Init flags & pointers
; 3. Save old interrupt vectors
; 4. Set new vectors
; 5. Exit all done
; Entry: None
; Return: AX = -1 if error
; AX = 0 if init processed ok
;
;
; Access the stack frame
;
push bp ; save c stack frame
mov bp,sp
push es ; save environment
push ds
push di
push si
mov ax,cs ; point to data
mov ds,ax
;
; Init the clock & root timer
;
mov timer_tick,0 ; current tick value
lea si,root_timer ; point to the timer
mov word ptr [si.ttype],0 ; type is interval timer
mov word ptr [si.counter],0 ; counter is at 0
mov word ptr [si.interval],1 ; interval is 1 tick
mov word ptr [si.event],0 ; no events thus far
mov word ptr [si.link],0 ; no other timers right now
mov word ptr [si.link+2],0
;
; Save int vector
;
mov ah,DOS_GET_VECTOR ; Save original interrupt vectors
mov al,TIMER_VECTOR
int DOS
mov word ptr oldint,bx
mov word ptr oldint+2,es
;
; Redirect ints to ISR
;
push ds
mov ax,SEG _dmtimer_isr
mov ds,ax
mov dx,OFFSET _dmtimer_isr
mov ah,DOS_SET_VECTOR ; Set new interrupt vectors
mov al,TIMER_VECTOR
int DOS
pop ds
;
; Exit all done
;
pop si ; restore registers
pop di
pop ds
pop es
pop bp ; clear out stack frame
ret
;
_dmtimer_init endp
_dmtimer_release proc far
;
;==========================
; Timer Release
;==========================
; Procedure: 1. Restore old INT vector
; 2. Exit all done
; Entry: None
; Return: None
;
push es ; Save
push ds
push di
push si
mov ax,cs ; Access local storage
mov ds,ax
;
; Restore int vector
;
mov dx,word ptr [oldint]
mov bx,word ptr [oldint+2]
mov ah,DOS_SET_VECTOR ; Save original interrupt vectors
mov al,TIMER_VECTOR
mov ds,bx
int DOS
;
; Exit all done
;
pop si ; restore registers
pop di
pop ds
pop es
ret
;
_dmtimer_release endp
_dmtimer_add proc far
;
;==========================
; Timer Add
;==========================
; Procedure: 1. Setup current timer
; 2. Hook to end of chain
; 3. Exit all done
; Entry: [BP+6] Offset of new timer block
; [BP+8] Segment of new timer block
; Return: None
;
;
; Access the stack frame
;
push bp ; save c stack frame
mov bp,sp
push es ; save environment
push ds
push di
push si
mov ax,cs ; point to data
mov ds,ax
mov di,[bp+6] ; get offset of new block
mov dx,[bp+8] ; get segment of new block
mov es,dx
;
; Init the new block
;
mov word ptr es:[di.event],0 ; no events thus far
mov word ptr es:[di.link],0 ; no other timers right now
mov word ptr es:[di.link+2],0
;
cmp word ptr es:[di.ttype],0 ; interval timer?
jne dmtimer_add_20 ; countdown if not
mov word ptr es:[di.counter],0 ; counter is at 0
jmp dmtimer_add_40 ; now add it to the chain
;
dmtimer_add_20:
mov ax,word ptr es:[di.interval] ; counter set to equal interval
mov word ptr es:[di.counter],ax
;
; Find the end of existing chain
;
dmtimer_add_40:
lea si,root_timer ; point to the timer
;
dmtimer_add_42:
mov ax,word ptr [si.link] ; at the null pointer?
or ax,word ptr [si.link+2]
jz dmtimer_add_60 ; add new to chain if so
mov ax,word ptr [si.link+2] ; get next timer block
mov si,word ptr [si.link]
mov ds,ax
jmp dmtimer_add_42 ; try again
;
; Add the new block to the chain
;
dmtimer_add_60:
cli ; freeze the world
mov word ptr [si.link],di ; store location of new block
mov word ptr [si.link+2],dx
sti ; alive again
;
; Exit all done
;
pop si ; restore registers
pop di
pop ds
pop es
pop bp
ret
;
_dmtimer_add endp
_dmtimer_sub proc far
;
;==========================
; Timer Remove
;==========================
; Procedure: 1. Set Previous pointer to next
; 3. Exit all done
; Entry: [BP+6] Offset of old timer block
; [BP+8] Segment of old timer block
; Return: AX = 0 if no error
; AX = -1 if old timer block not in chain
;
;
; Access the stack frame
;
push bp ; save c stack frame
mov bp,sp
push es ; Save
push ds
push di
push si
mov ax,cs ; Access local storage
mov ds,ax
mov di,[bp+6] ; get offset of old block
mov dx,[bp+8] ; get segment of old block
mov es,dx
;
; Find the old pointer to block
;
dmtimer_sub_40:
lea si,root_timer ; point to the timer
;
dmtimer_sub_42:
mov ax,word ptr [si.link] ; get the link offset
cmp ax,di ; match?
jne dmtimer_sub_44 ; next block if not
mov ax,word ptr [si.link+2] ; get the link segment
cmp ax,dx ; match?
je dmtimer_sub_60 ; remove old from chain if so
;
dmtimer_sub_44:
mov ax,word ptr [si.link+2] ; get next timer block
mov si,word ptr [si.link]
cmp ax,si ; are we at the end?
jne dmtimer_sub_46 ; continue if not
or ax,ax
jnz dmtimer_sub_46 ; continue if not
mov ax,-1 ; else flag as block not found
jmp dmtimer_sub_90
;
dmtimer_sub_46:
mov ds,ax ; set link segment
jmp dmtimer_sub_42 ; try again
;
; Remove old block from the chain
;
dmtimer_sub_60:
cli ; freeze the world
mov ax,word ptr es:[di.link] ; squeeze out the link
mov word ptr [si.link],ax
mov ax,word ptr es:[di.link+2]
mov word ptr [si.link+2],ax
sti ; alive again
xor ax,ax ; no errors
;
; Exit all done
;
dmtimer_sub_90:
pop si ; restore registers
pop di
pop ds
pop es
pop bp
ret
;
_dmtimer_sub endp
_dmtimer_isr proc far
;
;==========================
; Timer ISR
;==========================
; Procedure: 1. Test if active tick
; 2. Goto 17 if not
; 3. Get next block
; 4. Goto 17 if done
; 5. Test if interval
; 6. Goto 12 if not
; 7. Increment counter
; 8. If interval not reached goto 3
; 9. Reset counter
; 10. Increment event count
; 11. Goto xx
; 12. If event already tripped then goto 3
; 13. Countdown a tick
; 14. If not 0 then goto 3
; 15. Reset counter
; 16. Set event flag
; 17. Bump tick count
; 18. If tick count != 39 then goto 20
; 19. Reset tick count
; 20. Pass on to regular clock ISR
; Entry: None
; Return: None
;
push es ; Save
push ds
push di
push si
push bx
push ax
mov ax,cs ; Access local storage
mov ds,ax
;
; Restore int vector
;
lea bx,timer_table ; point to flag table
add bx,timer_tick ; add in current tick count (index)
cmp word ptr [bx],0 ; test if this is a 1/10 sec tick
jnz dmtimer_isr_10 ; process if so
jmp dmtimer_isr_90 ; else exit
;
; Get the first timer block
;
dmtimer_isr_10:
;
mov ax,cs ; point to 1st block
mov es,ax
lea di,root_timer
jmp dmtimer_isr_14
;
; Get next timer block
;
dmtimer_isr_12:
mov ax,word ptr es:[di.link+2] ; get next block
mov di,word ptr es:[di.link]
mov es,ax
;
; Exit if null block
;
dmtimer_isr_14:
mov ax,es ; test if null block
or ax,di
jnz dmtimer_isr_16 ; dispatch if not
jmp dmtimer_isr_90 ; else exit
;
dmtimer_isr_16:
cmp word ptr es:[di.ttype],0 ; is it an interval timer?
je dmtimer_isr_20 ; process if so
jmp dmtimer_isr_40 ; else assume countdown
;
; Process interval timer
;
dmtimer_isr_20:
inc word ptr es:[di.counter] ; bump the counter
mov ax,word ptr es:[di.counter] ; test if interval reached
cmp ax,word ptr es:[di.interval]
jnz dmtimer_isr_12 ; next timer block if not
mov word ptr es:[di.counter],0 ; reset the counter
inc word ptr es:[di.event] ; bump the event counter
jmp dmtimer_isr_12 ; next timer block
;
; Process countdown timer
;
dmtimer_isr_40:
cmp word ptr es:[di.event],0 ; test if event already flagged
jne dmtimer_isr_12 ; next timer block if not
dec word ptr es:[di.counter] ; bump the counter
jnz dmtimer_isr_12 ; next timer block if not expired
mov ax,word ptr es:[di.interval] ; reset the counter
mov word ptr es:[di.counter],ax ; reset the counter
inc word ptr es:[di.event] ; bump the event counter
jmp dmtimer_isr_12 ; next timer block
;
; Bump counter and adjust if needed
;
dmtimer_isr_90:
inc timer_tick ; bump timer tick counter
cmp timer_tick,91 ; at end?
jne dmtimer_isr_92 ; skip if not
mov timer_tick,0 ; else reset
;
; Exit all done
;
dmtimer_isr_92:
pop ax ; restore registers
pop bx
pop si
pop di
pop ds
pop es
jmp dword ptr cs:oldint ; pass on to regualr clock routine
;
_dmtimer_isr endp
DMIOSEG ends
END